package com.example.crashhandler;

import java.lang.Thread.UncaughtExceptionHandler;

import android.content.Context;
import android.content.pm.PackageInfo;
import android.content.pm.PackageManager.NameNotFoundException;
import android.util.Log;

/**
 * 类名：AppUncaughtExceptionHandler <br/>
 * 描述：App的异常崩溃捕捉处理 <br/>
 * 创建时间：2015年12月9日 上午9:53:25
 * @author wangmingshuo@ddsoucai.cn
 * @version 1.0
 */
public class AppUncaughtExceptionHandler implements UncaughtExceptionHandler {
	
	/** 上下文-主要用来获取APP信息 */
	private Context mContext;
	
	/** 系统默认的UncaughtException处理类  */
	private Thread.UncaughtExceptionHandler mDefaultHandler;
	
	/** AppUncaughtExceptionHandler单例 */
	private static AppUncaughtExceptionHandler sAppUncaughtExceptionHandler;

	private AppUncaughtExceptionHandler(Context context) {
		this.mContext = context.getApplicationContext();
		this.mDefaultHandler = Thread.getDefaultUncaughtExceptionHandler();
	}
	
	public static AppUncaughtExceptionHandler getInstance(Context context) {
		if (sAppUncaughtExceptionHandler == null) {
			sAppUncaughtExceptionHandler = new AppUncaughtExceptionHandler(context);
		}
		
		return sAppUncaughtExceptionHandler;
	}

	@Override
	public void uncaughtException(Thread thread, Throwable ex) {
		// 处理异常
		if (!handleException(thread, ex) && mDefaultHandler != null) {
			mDefaultHandler.uncaughtException(thread, ex);
		}
	}
	
	/**
	 * 自定义异常处理
	 * @param thread
	 * @param ex
	 * @return 是否处理异常，false-未处理异常，true已处理异常
	 */
	private boolean handleException(Thread thread, Throwable ex) {
		if (ex == null) {
			return false;
		}	
		
		Log.e("崩溃日志", getCrashReport(ex));
		
		String crashReport = getCrashReport(ex);
		// TODO 发送或保存崩溃日志
		
		try {
			Thread.sleep(300);
		} catch (InterruptedException e) {
			e.printStackTrace();
		}

		// TODO 退出程序，关闭了崩溃对话框
		android.os.Process.killProcess(android.os.Process.myPid());
		
		return true;
	}
	
	/**
	 * 获取App包信息
	 * @return 包信息
	 */
	private PackageInfo getPackageInfo() {
		PackageInfo info = null;
		try {
			info = mContext.getPackageManager().getPackageInfo(
					mContext.getPackageName(), 0);
		} catch (NameNotFoundException e) {
			e.printStackTrace(System.err);
		}
		if (info == null)
			info = new PackageInfo();
		return info;		
	}
	
	/**
	 * 获取APP崩溃异常报告
	 * @param ex VM抛出的错误类信息
	 * @return 崩溃异常报告
	 */
	private String getCrashReport(Throwable ex) {

		StringBuffer exceptionStr = new StringBuffer();
		
		PackageInfo packageInfo = getPackageInfo();
		
		exceptionStr.append("Version: " + packageInfo.versionName + "("
				+ packageInfo.versionCode + ")\n");
				
		exceptionStr.append("Android: " + android.os.Build.VERSION.RELEASE
				+ "(" + android.os.Build.MODEL + ")\n");
				
		exceptionStr.append("Exception: " + ex.getMessage() + "\n");
		
		StackTraceElement[] elements = ex.getStackTrace();
		
		for (int i = 0; i < elements.length; i++) {
			exceptionStr.append(elements[i].toString() + "\n");
		}
		
		Throwable cause = ex.getCause();  
		
		if(cause != null){
			exceptionStr.append("Cause By: " + cause.getMessage() + "\n");
			StackTraceElement[] causenots = cause.getStackTrace();
			for (int i = 0; i < causenots.length; i++) {
				exceptionStr.append(causenots[i].toString() + "\n");
			}
		}
		
		return exceptionStr.toString();
	}	

}
